﻿using Data.NHibernate.Args;
using Data.NHibernate.Entity;
using NHibernate;
using NHibernate.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Data.NHibernate
{
    public class Repository : IRepository
    {
        #region GetSession

        /// <summary>
        /// 获取Session对象
        /// </summary>
        private ISession iSession
        {
            get
            {
                string dataBaseName = "";
                if (ModelType != null)
                {
                    Type dataBaseAttributeType = typeof(DataBaseAttribute);
                    if (ModelType.IsDefined(dataBaseAttributeType, false))
                    {
                        object[] objectArr = ModelType.GetCustomAttributes(false);
                        foreach (var obj in objectArr)
                        {
                            if (obj.GetType().Equals(dataBaseAttributeType))
                            {
                                dataBaseName = ((DataBaseAttribute)objectArr[0]).DataBaseName;
                                break;
                            }
                        }
                    }
                }
                return Helper.GetSession(dataBaseName);
            }
        }

        /// <summary>
        /// 泛型类Type
        /// </summary>
        private Type ModelType
        {
            get;
            set;
        }

        #endregion

        /// <summary>
        /// 提供LINQ使用的可查询对象
        /// </summary>
        public IQueryable<T> AsQueryable<T>() where T : class
        {
            ModelType = typeof(T);
            IQueryable<T> result = iSession.Query<T>();
            return result;
        }

        /// <summary>
        /// 根据条件筛选
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达式(lamada)</param>
        /// <returns>IQueryable&lt;T&gt;</returns>
        public IQueryable<T> Find<T>(Expression<Func<T, bool>> expression) where T : class
        {
            ModelType = typeof(T);
            IQueryable<T> result = iSession.Query<T>().Where<T>(expression);
            return result;
        }

        /// <summary>
        /// 按条件查找，并排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达式(lamada)</param>
        /// <param name="SortList">排序条件集合</param>
        /// <returns>IQueryable&lt;T&gt;</returns>
        public IQueryable<T> Find<T>(Expression<Func<T, bool>> expression, List<OrderBy<T>> SortList) where T : class
        {
            ModelType = typeof(T);
            IQueryable<T> result = iSession.Query<T>().Where<T>(expression);
            foreach (var obj in SortList)
            {
                if (!obj.Sort)
                    result = result.OrderByDescending(obj.exp);
                else
                    result = result.OrderBy(obj.exp);
            }
            return result;
        }

        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达示</param>
        /// <param name="MyPage">PpageAttribute</param>
        /// <param name="SortList">List&lt;&lt;OrderBy&gt;&gt;：排序规则</param>
        /// <returns></returns>
        public IQueryable<T> PageList<T>(Expression<Func<T, bool>> expression, ref PageAttribute MyPage, List<OrderBy<T>> SortList = null) where T : class
        {
            IQueryable<T> result = SortList != null ? Find<T>(expression, SortList as List<OrderBy<T>>) : Find<T>(expression);
            MyPage.PageCount = result.Count();
            return result.Skip<T>((MyPage.PageIndex - 1) * MyPage.PageSize).Take(MyPage.PageSize);
        }

        /// <summary>
        /// 统计
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达式</param>
        /// <returns>long</returns>
        public long Count<T>(Expression<Func<T, bool>> expression) where T : class
        {
            ModelType = typeof(T);
            long lCount = iSession.Query<T>().Count<T>(expression);
            return lCount;
        }

        /// <summary>
        /// 是否存在
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达式</param>
        /// <returns>Boolen</returns>
        public bool Exists<T>(Expression<Func<T, bool>> expression) where T : class
        {
            ModelType = typeof(T);
            return iSession.Query<T>().Any(expression);
        }

        /// <summary>
        /// 根据主键id获取对像,没有返回NULL
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id">主键id</param>
        /// <returns>T object</returns>
        public T Get<T>(object id) where T : class
        {
            ModelType = typeof(T);
            T model = iSession.Get<T>(id);
            return model;
        }

        /// <summary>
        /// 根据主键id加载对像,没有返回对像默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id">主键id</param>
        /// <returns>T object</returns>
        public T Load<T>(object id) where T : class
        {
            ModelType = typeof(T);
            T model = iSession.Load<T>(id);
            return model;
        }

        /// <summary>
        /// 根据条件获取第一条记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达式(lamada)</param>
        /// <returns>T object</returns>
        public T First<T>(Expression<Func<T, bool>> expression) where T : class
        {
            ModelType = typeof(T);
            T model = iSession.Query<T>().FirstOrDefault<T>(expression);
            return model;
        }

        /// <summary>
        /// 根据对像删除记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item">object</param>
        public void Delete<T>(T item) where T : class
        {
            ModelType = typeof(T);
            var session = this.iSession;
            session.Delete(item);
            session.Flush();
        }

        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达示</param>
        /// <returns>int 受影响记录件数</returns>
        public int Delete<T>(Expression<Func<T, bool>> expression) where T : class
        {
            ModelType = typeof(T);
            List<T> list = (from p in Find<T>(expression)
                            select p).ToList<T>();
            int i = DeleteList<T>(list);
            return i;
        }

        /// <summary>
        /// 删除全部
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>int 删除受影响全部</returns>
        public int DeleteAll<T>() where T : class
        {
            ModelType = typeof(T);
            List<T> list = (from p in AsQueryable<T>()
                            select p).ToList<T>();
            int i = DeleteList<T>(list);
            return i;
        }

        /// <summary>
        /// 批量删除(公共方法)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">List&lt;T&gt;</param>
        /// <returns>int</returns>
        int DeleteList<T>(List<T> list) where T : class
        {
            ModelType = typeof(T);
            int i = 0;
            var session = this.iSession;
            using (ITransaction dlist = this.iSession.BeginTransaction())
            {
                try
                {
                    foreach (var obj in list)
                    {
                        session.Delete(obj);
                        i++;
                    }
                    dlist.Commit();
                }
                catch
                {
                    dlist.Rollback();
                    i = 0;
                }
            }
            return i;
        }

        /// <summary>
        /// 只存对像
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item">对像</param>
        /// <returns>object 主键ID</returns>
        public object Save<T>(T item) where T : class
        {
            ModelType = typeof(T);
            var session = this.iSession;
            object obj = session.Save(item);
            session.Flush();
            return obj;
        }

        /// <summary>
        /// 保存或更新一个已存在的数据对象 注：web开发中请单独使用Save或者Update方法
        /// </summary>
        /// <param name="item">待保存/更新的对象</param>
        /// <returns>返回已保存的对象</returns>
        public T SaveOrUpdate<T>(T item) where T : class
        {
            ModelType = typeof(T);
            var session = this.iSession;
            session.SaveOrUpdate(item);
            session.Flush();
            return item;
        }

        /// <summary>
        /// 更新记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item">T 对像</param>
        public void Update<T>(T item) where T : class
        {
            ModelType = typeof(T);
            var session = this.iSession;
            session.Update(item);
            session.Flush();
        }
    }
}
